import Constant from './constant.js';
import Utils from './index.js';
import CesiumZh from "./cesium-local";
import Compass from './compass';
import {
  uuid
} from 'vue-uuid';
import {
  ElMessage,
  ElMessageBox
} from 'element-plus';

export default class BasicCesium {
  constructor(container, option) {
    this.viewer = this.initCesium(container, option);
    if (option != null) this.defaultConfig(this.viewer)
  }

  initCesium(container, option) {
    Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI5ZDI4YTYwZC1hNDMwLTQ1MDgtOWM3NS0zMzc2YjcxMjZmYjEiLCJpZCI6MTIyNzc1LCJpYXQiOjE2ODM4MDIzMjh9.qSaIwYJpdCexW1dEJhZDohzKFh9P79gR1Yb7ROEjCyU'
    let _default = {
      shouldAnimate: false,
      animation: false, //是否创建动画小器件，左下角仪表  
      timeline: false, //是否显示时间轴  
      baseLayerPicker: true, //是否显示图层选择器   
      fullscreenButton: false, //是否显示全屏按钮
      geocoder: false, //是否显示geocoder小器件，右上角查询按钮
      homeButton: false, //是否显示Home按钮  
      infoBox: false, //是否显示信息框  
      debugShowFramesPerSecond: true,
      // sceneModePicker: true, //是否显示3D/2D选择器   
      selectionIndicator: false, //是否显示选取指示器组件 
      navigationHelpButton: false, //是否显示右上角的帮助按钮  
      scene3DOnly: true, //如果设置为true，则所有几何图形以3D模式绘制以节约GPU资源 
      clock: new Cesium.Clock(), //用于控制当前时间的时钟对象
      selectedImageryProviderViewModel: undefined, //当前图像图层的显示模型，仅baseLayerPicker设为true有意义 
      // imageryProviderViewModels: Terrain.createDefaultImageryProviderViewModels(), //可供BaseLayerPicker选择的图像图层ProviderViewModel数组 
      selectedTerrainProviderViewModel: undefined, //当前地形图层的显示模型，仅baseLayerPicker设为true有意义 
      // terrainProviderViewModels: Terrain.createDefaultTerrainProviderViewModels(), //可供BaseLayerPicker选择的地形图层ProviderViewModel数组   
      terrainProvider: new Cesium.EllipsoidTerrainProvider(), //地形图层提供者，仅baseLayerPicker设为false有意义 
      fullscreenElement: document.body, //全屏时渲染的HTML元素,    
      useDefaultRenderLoop: true, //如果需要控制渲染循环，则设为true    
      targetFrameRate: undefined, //使用默认render loop时的帧率    
      showRenderLoopErrors: false, //如果设为true，将在一个HTML面板中显示错误信息    
      automaticallyTrackDataSourceClocks: true, //自动追踪最近添加的数据源的时钟设置    
      sceneMode: Cesium.SceneMode.SCENE3D, //初始场景模式    
      mapProjection: new Cesium.WebMercatorProjection(), //地图投影体系    
      dataSources: new Cesium.DataSourceCollection(), //需要进行可视化的数据源的集合  
      skipLevelOfDetail: true,
      baseScreenSpaceError: 1024,
      maximumScreenSpaceError: 328, // 数值加大，能让最终成像变模糊
      skipScreenSpaceErrorFactor: 16,
      skipLevels: 1,
      immediatelyLoadDesiredLevelOfDetail: false,
      navigationInstructionsInitiallyVisible: false,
      loadSiblings: true, // 如果为true则不会在已加载完概况房屋后，自动从中心开始超清化房屋
      cullWithChildrenBounds: true,
      cullRequestsWhileMoving: true,
      cullRequestsWhileMovingMultiplier: 10, // 值越小能够更快的剔除
      preloadWhenHidden: true,
      preferLeaves: true,
      maximumMemoryUsage: 128, // 内存分配变小有利于倾斜摄影数据回收，提升性能体验
      progressiveResolutionHeightFraction: 0.2, // 数值偏于0能够让初始加载变得模糊
      dynamicScreenSpaceErrorDensity: 0.8, // 数值加大，能让周边加载变快
      dynamicScreenSpaceErrorFactor: 1, // 不知道起了什么作用没，反正放着吧先
      dynamicScreenSpaceError: true, // 根据测试，有了这个后，会在真正的全屏加载完之后才清晰化房屋
      skyAtmosphere: false,
      contextOptions: { //截屏设置
        webgl: {
          alpha: false,
          depth: true,
          stencil: false,
          antialias: true,
          powerPreference: 'high-performance',
          premultipliedAlpha: true,
          preserveDrawingBuffer: false,
          failIfMajorPerformanceCaveat: false,
        },
        allowTextureFilterAnisotropic: true,
        requestWebgl2: false,
      }
    }
    if (Utils.nullBool(option)) {
      option = _default;
    } else {
      option = Object.assign(_default, option);
    }
    if (Utils.strBool(container)) {
      return new Error('DOM 没有定义');
    }
    let viewer = new Cesium.Viewer(container, this.buildOption(option));

    this.updateConfig(viewer, {
      isCompass: false
    })
    return viewer;
  }

  guid() {
    return uuid.v1();
  }

  defaultConfig(viewer) {
    viewer._cesiumWidget._creditContainer.style.display = "none";
    viewer.resolutionScale = window.devicePixelRatio; //dpr优化
    viewer.scene.postProcessStages.fxaa.enabled = false; //去锯齿 是文字清晰
    viewer.scene.fog.enabled = true;
    viewer.scene.fog.density = 0.0005;
    // viewer.scene.skyAtmosphere.brightnessShift = -0.33
    viewer.scene.fog.minimumBrightness = 0.03;
    viewer.scene.globe.showGroundAtmosphere = false;
    viewer.scene.brightness = 1.0

    viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
      Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
    );
    //相机的高度的最小值 
    viewer.scene.screenSpaceCameraController.minimumZoomDistance = 50;
    //相机高度的最大值
    viewer.scene.screenSpaceCameraController.maximumZoomDistance = 120000000;
    // 设置相机缩小时的速率
    viewer.scene.screenSpaceCameraController._minimumZoomRate = 30000;
    //设置相机放大时的速率
    viewer.scene.screenSpaceCameraController._maximumZoomRate = 5906376272000;
    viewer.scene.globe.terrainExaggeration = 2;
    viewer.scene.globe.terrainExaggerationRelativeHeight = 2400;
    //默认的Cesium会加载一个bingMap底图，这个地图网络不太好，一般要先去掉这个默认的
    // viewer.imageryLayers.remove(viewer.imageryLayers.get(0));
    viewer.scene.globe.enableLighting = false; //对大气和雾启用动态照明效果
  }

  buildOption(option) {
    Utils.arrayForEach(Constant.PLUGIN, function (key) {
      if (!option[key]) option[key] = false;
    });
    return option;
  }

  updateConfig(viewer, option = {
    isCompass: false
  }) {
    let longitude = 34.6169472;
    let latitude = 47.6458037;
    let height = 10000000;
    let position = Cesium.Cartesian3.fromDegrees(longitude, latitude, height);
    //罗盘
    if (option.isCompass) {
      new Compass(viewer, {
        position
      });
    }

    //汉化
    CesiumZh.load();
    //帧率
    viewer.scene.debugShowFramesPerSecond = true;
    Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(longitude - 1, latitude - 1, longitude + 1, latitude + 1);
    //初始化位置
    viewer.camera.setView({
      destination: Cesium.Cartesian3.fromDegrees(
        longitude,
        latitude,
        height
      )
    });
  }

  //获取鼠标点击位置经纬度信息
  getMouseInfo(position) {
    let viewer = this.viewer;
    //屏幕坐标转世界坐标
    let cartesian3 = this.xyToWorld(position);
    if (cartesian3 == undefined) {
      ElMessage.warning('超出球体范围')
      return false;
    }
    let div = document.querySelector('#mouseInfo');

    let cHeight = this.cameraHeight();
    let cartesian2 = this.worldToXy(cartesian3);
    // roll 左右歪头脖子往肩膀上靠 heading 左右转向 头部水平旋转 pitch 抬头低头
    let pitch = Cesium.Math.toDegrees(viewer.camera.pitch);
    let roll = Cesium.Math.toDegrees(viewer.camera.roll);
    let heading = Cesium.Math.toDegrees(viewer.camera.heading);

    let cartographic = Cesium.Cartographic.fromCartesian(cartesian3)
    let longitude = Cesium.Math.toDegrees(cartographic.longitude);
    let latitude = Cesium.Math.toDegrees(cartographic.latitude);

    this.terrainHeight((height) => {
      let array = [
        '<span>经度</span>' + longitude.toFixed(6),
        '<span>纬度</span>' + latitude.toFixed(6),
        '<span>海拔</span>' + height.toFixed(1),
        '<span>方向</span>' + heading.toFixed(1),
        '<span>俯仰角</span>' + pitch.toFixed(1),
        '<span>视高</span>' + cHeight.toFixed(1),
        '<span>x</span>' + cartesian2.x.toFixed(1),
        '<span>y</span>' + cartesian2.y.toFixed(1),
      ]
      if (div != undefined) {
        div.innerHTML = `${array.join('&nbsp;')}`;
      }
      console.log(JSON.stringify([longitude, latitude]))
    }, cartesian3)
  }

  //屏幕坐标转世界坐标 
  xyToWorld(position) {
    let picks = this.viewer.scene.drillPick(position);
    let cartesian3;
    let isOn3dtiles = false;
    for (var i = 0; i < picks.length; i++) {
      //模型上拾取
      if (picks[i] instanceof Cesium.Cesium3DTileFeature) {
        isOn3dtiles = true;
      }
    }
    if (isOn3dtiles) {
      cartesian3 = this.viewer.scene.pickPosition(position);
    } else {
      var ray = this.viewer.camera.getPickRay(position);
      if (!ray) return null;
      cartesian3 = this.viewer.scene.globe.pick(ray, this.viewer.scene);
    }
    return cartesian3;
  }

  //世界坐标系转二维坐标系
  worldToXy(cartesian3) {
    return Cesium.Cartesian2.fromCartesian3(cartesian3);
  }

  //经纬度转世界坐标
  lnglatToWorld(lng, lat, height) {
    return Cesium.Cartesian3.fromDegrees(lng, lat, height)
  }

  // 世界坐标系转经纬度
  worldToLnglat(cartesian3) {
    let cartographic = Cesium.Cartographic.fromCartesian(cartesian3);
    let longitude = Cesium.Math.toDegrees(cartographic.longitude);
    let latitude = Cesium.Math.toDegrees(cartographic.latitude);
    let alt = cartographic.height;
    return {
      lng: longitude,
      lat: latitude,
      height: alt
    }
  }

  //获取相机高度(视高)
  cameraHeight() {
    let viewer = this.viewer;
    if (viewer) {
      let scene = viewer.scene;
      let ellipsoid = scene.globe.ellipsoid;
      let height = ellipsoid.cartesianToCartographic(viewer.camera.position).height;
      return height;
    }
    return 'viewer is undefined';
  }

  //获取地形高度添加地图文字图标
  terrainHeight(fn, position) {
    if (this.viewer.terrainProvider instanceof Cesium.EllipsoidTerrainProvider) {
      fn ? fn(0) : null;
    } else {
      //获取地形高度
      let cartographic = Cesium.Cartographic.fromCartesian(position);
      let longitude = Cesium.Math.toDegrees(cartographic.longitude);
      let latitude = Cesium.Math.toDegrees(cartographic.latitude);
      let positions = [
        Cesium.Cartographic.fromDegrees(longitude, latitude),
      ];
      let promise = Cesium.sampleTerrainMostDetailed(this.viewer.terrainProvider, positions);
      promise.then((res) => {
        let terrainHeight = res[0].height
        fn ? fn(terrainHeight) : null;
      })
    }
  }

  //添加标签
  entityBillboard(position, buildOption = {}) {
    let uuid = this.guid()
    let option = {
      id: uuid,
      position: position,
      billboard: {
        img: 'img/point.png',
        width: 12,
        height: 12,
        verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
        disableDepthTestDistance: Number.POSITIVE_INFINITY
      }
    }
    let newOption = Object.assign(option, buildOption)
    return this.viewer.entities.add(newOption)
  }

  //添加点
  entityPoint(position, color = '#de4a4a', text = '', buildOption = {}) {
    let uuid = this.guid()
    let option = {
      id: uuid,
      position: position,
      point: {
        color: Cesium.Color.fromCssColorString(color),
        pixelSize: 10,
        outlineColor: Cesium.Color.fromCssColorString('#ffff00'),
        outlineWidth: 2,
        disableDepthTestDistance: Number.POSITIVE_INFINITY,
        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
      },
      label: {
        text: text,
        font: "14px monospace",
        fillColor: Cesium.Color.fromCssColorString("#ffff00"),
        backgroundColor: Cesium.Color.fromCssColorString('#1d3350').withAlpha(0.6),
        showBackground: true,
        verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
        pixelOffset: new Cesium.Cartesian2(0, -10), // 偏移量
        disableDepthTestDistance: Number.POSITIVE_INFINITY,
        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
      }
    }
    let newOption = Object.assign(option, buildOption)
    return this.viewer.entities.add(newOption)
  }

  //画线
  entityPolyline(positions, color = '#de4a4a', buildOption = {}) {
    let uuid = this.guid()
    let option = {
      id: uuid,
      polyline: {
        show: true,
        positions: new Cesium.CallbackProperty(() => {
          return positions;
        }, false),
        width: 3,
        material: Cesium.Color.fromCssColorString(color),
        depthFailMaterial: new Cesium.PolylineDashMaterialProperty({
          color: Cesium.Color.RED,
        }),
        clampToGround: true,
        classificationType: Cesium.ClassificationType.BOTH,
      }
    }
    let newOption = Object.assign(option, buildOption)
    return this.viewer.entities.add(newOption)
  }

  //画面
  entityPolygon(positions, color = '#de4a4a', buildOption = {}) {
    let uuid = this.guid()
    let option = {
      id: uuid,
      polygon: {
        hierarchy: new Cesium.CallbackProperty(() => {
          return new Cesium.PolygonHierarchy(positions);
        }, false),
        material: Cesium.Color.fromCssColorString(color).withAlpha(0.6),
        outline: true,
        outlineColor: Cesium.Color.fromCssColorString('#ffff00'),
        outlineWidth: 2
      }
    }
    let newOption = Object.assign(option, buildOption)
    return this.viewer.entities.add(newOption)
  }

  activeEntityPolygon(update, config, buildOption) {
    let uuid = this.guid()
    let option = {
      id: uuid,
      polygon: new Cesium.PolygonGraphics({
        hierarchy: new Cesium.CallbackProperty(update, false),
        show: true,
        fill: true,
        ...config,
      })
    }
    let newOption = Object.assign(option, buildOption)
    return this.viewer.entities.add(newOption)
  }

  //画圆
  entityCircle(position, color = '#de4a4a', buildOption = {}) {
    let uuid = this.guid()
    let distance = Cesium.Cartesian3.distance(position[0], position[1]);
    let option = {
      id: uuid,
      position: position[0],
      ellipse: {
        semiMinorAxis: distance,
        semiMajorAxis: distance,
        material: new Cesium.StripeMaterialProperty({
          evenColor: Cesium.Color.fromCssColorString(color).withAlpha(0.5),
          oddColor: Cesium.Color.BLUE.withAlpha(0.5),
          repeat: 10.0,
        }),
        outline: true,
        outlineColor: Cesium.Color.fromCssColorString(color),
        outlineWidth: 4,
      }
    }
    let newOption = Object.assign(option, buildOption)
    return this.viewer.entities.add(newOption)
  }

  //画矩形
  entityRectangle(positions, color = '#a64968', buildOption = {}) {
    let uuid = this.guid()
    let option = {
      id: uuid,
      rectangle: {
        coordinates: Cesium.Rectangle.fromCartesianArray(positions),
        material: Cesium.Color.fromCssColorString(color).withAlpha(0.6),
        // rotation: Cesium.Math.toRadians(-40.0),
        outline: true,
        outlineColor: Cesium.Color.fromCssColorString(color),
        outlineWidth: 1,
        // stRotation: Cesium.Math.toRadians(90),
      }
    }
    let newOption = Object.assign(option, buildOption)
    return this.viewer.entities.add(newOption)
  }

  //entity模型
  entityModel(position, buildOption = {}) {
    let uuid = this.guid()
    let option = {
      id: uuid,
      position: position,
      disableDepthTestDistance: 99000000,
    };
    let newOption = Object.assign(option, buildOption)
    return this.viewer.entities.add(newOption)
  }

  //动态绑定移动柱体
  createScan(entity) {
    let property = entity.position;
    let that = this;
    var _update = function () {
      var position = property.getValue(that.viewer.clock.currentTime);
      var cartographic = that.viewer.scene.globe.ellipsoid.cartesianToCartographic(position);
      var lat = Cesium.Math.toDegrees(cartographic.latitude),
        lng = Cesium.Math.toDegrees(cartographic.longitude);
      return Cesium.Cartesian3.fromDegrees(lng, lat, 0);
    };
    var _length = function () {
      var position = property.getValue(that.viewer.clock.currentTime);
      var cartographic = that.viewer.scene.globe.ellipsoid.cartesianToCartographic(position);
      return cartographic.height * 2;
    }
    let scan = this.viewer.entities.add({
      position: new Cesium.CallbackProperty(_update, false),
      cylinder: {
        HeightReference: Cesium.HeightReference.RELATIVE_TO_GROUND, //表示相对于地形的位置。
        //长度
        length: new Cesium.CallbackProperty(_length, false),
        topRadius: 0, //顶点半径
        bottomRadius: 12000, //底部半径
        material: new Cesium.Color(0, 1, 1, .4),
        slices: 10
      }
    })
    return scan
  }

  mouseStyle(sty = 'crosshair') {
    this.viewer._container.style.cursor = sty
  }

  //获取pick
  mousePicked(position) {
    let pick = this.viewer.scene.pick(position);
    if (Cesium.defined(pick) && pick.id) {
      return pick;
    }
    return null;
  }

  removeByEntity(entity) {
    this.viewer.entities.remove(entity);
  }

  removeById(uuid) {
    this.viewer.entities.removeById(uuid);
  }

  //创建路线
  createPath(position) {
    let entity = this.viewer.entities.add({
      position: position,
      path: this.getPath()
    });
    return entity;
  }

  //路径
  getPath() {
    return new Cesium.PathGraphics({
      show: true,
      leadTime: 0,
      trailTime: 60,
      width: 20,
      resolution: 1,
      //设置航线样式，线条颜色，内发光粗细，航线宽度等
      material: new Cesium.PolylineGlowMaterialProperty({
        glowPower: 0.3,
        taperPower: 0.3,
        color: Cesium.Color.fromCssColorString('#a64968')
      }),
    })
  }

  //取消地图锁定
  transformLookAt() {
    this.viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
  }
}